package coupon

import (
	"context"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/utils/pointy"
	"mall/service/backend/api/internal/logic/promotion/util"
	"mall/service/backend/api/internal/logic/utils"
	"mall/service/backend/api/internal/logic/utils/parse"
	"mall/service/backend/api/internal/svc"
	"mall/service/backend/api/internal/types"
	"mall/service/backend/common/enum/errorcode"
	"mall/service/backend/common/errorx"
	"mall/service/backend/common/i18n"
	"mall/service/product/rpc/productclient"
	"mall/service/promotion/rpc/promotionclient"

	"github.com/zeromicro/go-zero/core/logx"
)

type GetCouponProductListLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetCouponProductListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetCouponProductListLogic {
	return &GetCouponProductListLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetCouponProductListLogic) GetCouponProductList(req *types.CouponProductListReq) (*types.CouponProductListResp, error) {
	if req.CouponId == nil || *req.CouponId == 0 {
		return nil, errorx.NewCodeError(errorcode.InvalidArgument,
			l.svcCtx.Trans.Trans(l.ctx, "common.validationError"))
	}

	page, pageSize := parse.ParsePageInfo(
		req.Current,
		req.PageSize,
		l.svcCtx.Config.Query.DefaultAmount,
		l.svcCtx.Config.Query.MaxAmount,
	)

	orderBys := util.ParseSorter(req.Sorter)
	filterBys := util.ParseFilter(req.Filter)

	res, err := l.svcCtx.PromotionRpc.BackendGetCouponProductList(l.ctx, &promotionclient.CouponProductListReq{
		Page:        page,
		PageSize:    pageSize,
		CouponId:    req.CouponId,
		BrandId:     req.BrandId,
		CategoryId:  req.CategoryId,
		ProductId:   req.ProductId,
		ProductType: req.ProductType,
		OrderBy:     orderBys,
		FilterBy:    filterBys,
	})
	if err != nil {
		return nil, err
	}

	resp := &types.CouponProductListResp{
		BaseDataInfo: types.BaseDataInfo{
			Success: true,
			Msg:     l.svcCtx.Trans.Trans(l.ctx, i18n.Success),
		},
		Data: types.CouponProductListInfo{
			BaseListInfo: types.BaseListInfo{
				Current:  page,
				PageSize: pageSize,
			},
		},
	}
	var total uint64

	if len(res.List) > 0 {
		var ids []string
		var bids []string
		idSortMap := make(map[uint64]*uint32)
		bidSortMap := make(map[uint64]*uint32)
		for _, v := range res.List {
			if v.BrandId != nil && *v.BrandId > 0 {
				bids = append(bids, strconv.FormatInt(int64(*v.BrandId), 10))
				bidSortMap[*v.BrandId] = v.Sort
			}
			if v.ProductId != nil && *v.ProductId > 0 {
				ids = append(ids, strconv.FormatInt(int64(*v.ProductId), 10))
				idSortMap[*v.ProductId] = v.Sort
			}
		}

		productMap := make(map[uint64]struct{})
		if len(bids) > 0 {
			data, err := l.svcCtx.ProductRpc.BackendGetProductList(l.ctx, &productclient.ProductListReq{
				BrandIds:  pointy.GetPointer(strings.Join(bids, ",")),
				WithEntry: pointy.GetPointer(uint32(1)),
			})
			if err != nil {
				return nil, err
			}

			if len(data.List) > 0 {
				brandMap := make(map[uint64]struct{})
				for _, v := range data.List {
					if v.Id != nil && *v.Id > 0 {
						if _, ok := productMap[*v.Id]; ok {
							continue
						}

						productMap[*v.Id] = struct{}{}
					}

					var media []*types.MediaInfo
					if len(v.Media) > 0 {
						for _, m := range v.Media {
							var url string
							if m.Url != nil && len(*m.Url) > 0 {
								url = *m.Url
							}
							if len(url) == 0 && m.Uri != nil && len(*m.Uri) > 0 {
								url = *m.Uri
							}
							filename, mimeType, metaData := utils.ParseMetaData(m.MetaData)
							media = append(media, &types.MediaInfo{
								Uid:       m.Uid,
								Id:        m.Id,
								Thumbnail: m.Thumbnail,
								Order:     m.Order,
								Url:       pointy.GetPointer(url),
								Name:      pointy.GetPointer(filename),
								MimeType:  pointy.GetPointer(mimeType),
								AltText:   m.AltText,
								MetaData:  pointy.GetPointer(metaData),
							})
						}
					}
					var brandId *uint64
					var brandName *string
					var brandSlug *string
					var sort *uint32
					if len(v.Relations) > 0 {
						for _, entry := range v.Relations {
							if entry.Key != nil && *entry.Key == globalkey.ProductRelationNameBrand {
								brandId = entry.Id
								brandName = entry.Name
								brandSlug = entry.Slug
								if brandId != nil && *brandId > 0 {
									if sorter, ok := bidSortMap[*brandId]; ok {
										sort = sorter
									}
									if _, ok := brandMap[*brandId]; !ok {
										resp.Data.BrandList = append(resp.Data.BrandList, &types.CouponBrandInfo{
											Id:    brandId,
											Title: brandName,
											Slug:  brandSlug,
										})
										brandMap[*brandId] = struct{}{}
									}
								}
							}
						}
					}

					resp.Data.List = append(resp.Data.List, &types.CouponProductInfo{
						Id:        v.Id,
						Title:     v.Title,
						Slug:      v.Slug,
						BrandId:   brandId,
						BrandName: brandName,
						BrandSlug: brandSlug,
						Sort:      sort,
						Status:    v.Status,
						Media:     media,
						CanRemove: pointy.GetPointer(false),
					})
				}
			}
		}
		if len(ids) > 0 {
			data, err := l.svcCtx.ProductRpc.BackendGetProductList(l.ctx, &productclient.ProductListReq{
				Ids:       pointy.GetPointer(strings.Join(ids, ",")),
				WithEntry: pointy.GetPointer(uint32(1)),
			})
			if err != nil {
				return nil, err
			}

			if len(data.List) > 0 {
				for _, v := range data.List {
					var sort *uint32
					if v.Id != nil && *v.Id > 0 {
						if _, ok := productMap[*v.Id]; ok {
							continue
						}

						productMap[*v.Id] = struct{}{}
						if sorter, ok := idSortMap[*v.Id]; ok {
							sort = sorter
						}
					}

					var media []*types.MediaInfo
					if len(v.Media) > 0 {
						for _, m := range v.Media {
							var url string
							if m.Url != nil && len(*m.Url) > 0 {
								url = *m.Url
							}
							if len(url) == 0 && m.Uri != nil && len(*m.Uri) > 0 {
								url = *m.Uri
							}
							filename, mimeType, metaData := utils.ParseMetaData(m.MetaData)
							media = append(media, &types.MediaInfo{
								Uid:       m.Uid,
								Id:        m.Id,
								Thumbnail: m.Thumbnail,
								Order:     m.Order,
								Url:       pointy.GetPointer(url),
								Name:      pointy.GetPointer(filename),
								MimeType:  pointy.GetPointer(mimeType),
								AltText:   m.AltText,
								MetaData:  pointy.GetPointer(metaData),
							})
						}
					}
					var brandId *uint64
					var brandName *string
					var brandSlug *string
					if len(v.Relations) > 0 {
						for _, entry := range v.Relations {
							if entry.Key != nil && *entry.Key == globalkey.ProductRelationNameBrand {
								brandId = entry.Id
								brandName = entry.Name
								brandSlug = entry.Slug
							}
						}
					}

					resp.Data.List = append(resp.Data.List, &types.CouponProductInfo{
						Id:        v.Id,
						Title:     v.Title,
						Slug:      v.Slug,
						BrandId:   brandId,
						BrandName: brandName,
						BrandSlug: brandSlug,
						Sort:      sort,
						Status:    v.Status,
						Media:     media,
						CanRemove: pointy.GetPointer(true),
					})
				}
			}
		}
		resp.Data.Total = total
	}

	return resp, nil
}
